package com.fangcun.common.util.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.fangcun.common.util.PublicMethod;

public class HttpClientTools {
	private static Logger logger = LoggerFactory.getLogger(HttpClientTools.class);
	// 默认超时时间：10s
	public static final int TIME_OUT = 120 * 1000;
	private static PoolingHttpClientConnectionManager cm = null;
	static {
		LayeredConnectionSocketFactory sslsf = null;
		try {
			sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
		} catch (NoSuchAlgorithmException e) {
			logger.error("创建SSL连接失败...");
		}
		Registry<ConnectionSocketFactory> sRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslsf)
				.register("http", new PlainConnectionSocketFactory()).build();
		cm = new PoolingHttpClientConnectionManager(sRegistry);
		// 设置最大的连接数
		cm.setMaxTotal(500);
		// 设置每个路由的基础连接数【默认，每个路由基础上的连接不超过2个，总连接数不能超过20】
		cm.setDefaultMaxPerRoute(200);
	}

	public static CloseableHttpClient getHttpClient() {
		CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
		return httpClient;
	}

	public static String doPostJson(String url, String json, Map<String, Object> headerMap) {
		try {
			CloseableHttpClient httpclient = HttpClients.createDefault();
			HttpPost httpPost = new HttpPost(url);// 创建httpPost
			httpPost.setHeader("Accept", "application/json");
			httpPost.setHeader("Content-Type", "application/json");
			if (headerMap != null) {
				Iterator<Map.Entry<String, Object>> it = headerMap.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, Object> entry = it.next();
					httpPost.setHeader(entry.getKey(), entry.getValue() == null ? null : entry.getValue().toString());
				}
			}
			String charSet = "UTF-8";
			StringEntity entity = new StringEntity(json, charSet);
			httpPost.setEntity(entity);
			CloseableHttpResponse response = null;
			try {

				response = httpclient.execute(httpPost);
				StatusLine status = response.getStatusLine();
				int state = status.getStatusCode();
				if (state == HttpStatus.SC_OK) {
					HttpEntity responseEntity = response.getEntity();
					String jsonString = EntityUtils.toString(responseEntity);
					return jsonString;
				} else {
					System.err.println("请求返回:" + state + "(" + url + ")");
				}
			} finally {
				if (response != null) {
					try {
						response.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				try {
					httpclient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String doPostXml(String url, String xml) throws Exception {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(url);// 创建httpPost
		httpPost.setHeader("Accept", "application/xml");
		httpPost.setHeader("Content-Type", "application/xml");
		String charSet = "UTF-8";
		StringEntity entity = new StringEntity(xml, charSet);
		httpPost.setEntity(entity);
		CloseableHttpResponse response = null;
		try {
			response = httpclient.execute(httpPost);
			StatusLine status = response.getStatusLine();
			int state = status.getStatusCode();
			if (state == HttpStatus.SC_OK) {
				HttpEntity responseEntity = response.getEntity();
				String jsonString = EntityUtils.toString(responseEntity, charSet);
				return jsonString;
			} else {
				System.err.println("请求返回:" + state + "(" + url + ")");
			}
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            路径
	 * @return
	 */
	public static String get(String url, Map<String, Object> header, Map<String, Object> param) {
		String jsonResult = null;
		CloseableHttpClient httpClient = getHttpClient();
		// get请求返回结果
		CloseableHttpResponse response = null;
		try {
			// 配置请求超时时间
			StringBuffer paramStr = new StringBuffer();
			if (param != null && param.size() > 0) {
				for (String key : param.keySet()) {
					paramStr.append(key + "=");
					if (StringUtils.isEmpty(param.get(key))) {
						paramStr.append("&");
					} else {
						String value = param.get(key).toString();
						try {
							value = URLEncoder.encode(value, "UTF-8");
						} catch (UnsupportedEncodingException e) {
							e.printStackTrace();
						}
						paramStr.append(value + "&");
					}
				}
				url += paramStr;
			}
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
			// 发送get请求
			HttpGet request = new HttpGet(url);
			request.setConfig(requestConfig);
			// 设置头信息
			if (header != null) {
				for (Map.Entry<String, Object> entry : header.entrySet()) {
					request.addHeader(entry.getKey(), entry.getValue().toString());
				}
			}
			response = httpClient.execute(request);
			// 读取服务器返回过来的json字符串数据
			jsonResult = EntityUtils.toString(response.getEntity(), "UTF-8");
			// 请求发送成功，并得到响应
			if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				logger.error("get请求提交失败={}:{}->response:{}", url, response.getStatusLine().getStatusCode(), jsonResult);
			}
		} catch (IOException e) {
			logger.error("get请求提交失败:" + url, e);
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
					response.close();
				} catch (IOException e) {
					logger.error("关闭response失败:", e);
				}
			}
		}
		return jsonResult;
	}

	public static String post(String url, Map<String, Object> header, Map<String, Object> param, String entity) {
		String jsonResult = null;
		CloseableHttpClient httpClient = getHttpClient();
		// get请求返回结果
		CloseableHttpResponse response = null;
		try {
			// 配置请求超时时间
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
			// 发送get请求
			HttpPost request = new HttpPost(url);
			request.setConfig(requestConfig);
			// 设置头信息
			if (header != null) {
				for (Map.Entry<String, Object> entry : header.entrySet()) {
					request.addHeader(entry.getKey(), entry.getValue().toString());
				}
			}
			// 设置请求参数
			if (param != null) {
				List<NameValuePair> formparams = new ArrayList<NameValuePair>();
				for (Map.Entry<String, Object> entry : param.entrySet()) {
					// 给参数赋值
					formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
				}
				UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
				request.setEntity(urlEncodedFormEntity);
			}
			// 设置实体 优先级高
			if (!StringUtils.isEmpty(entity)) {
				boolean isSetContentType = true;
				if (header != null && header.containsKey("Content-Type")) {
					isSetContentType = false;
				}

				if (isSetContentType) {
					if (PublicMethod.isXML(entity)) {
						request.addHeader("Content-Type", "application/xml");
					}
					if (PublicMethod.isJson(entity)) {
						request.addHeader("Content-Type", "application/json");
					}
				}
				// 定义请求实体
				HttpEntity requestEntity = new StringEntity(entity, "UTF-8");
				request.setEntity(requestEntity);
			}

			response = httpClient.execute(request);
			// 读取服务器返回过来的json字符串数据
			jsonResult = EntityUtils.toString(response.getEntity(), "UTF-8");
			// 请求发送成功，并得到响应
			if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				logger.error("post请求提交失败={}:{}->response:{}", url, response.getStatusLine().getStatusCode(), jsonResult);
			}
		} catch (IOException e) {
			logger.error("post请求提交失败:" + url, e);
		} finally {
			if (response != null) {
				try {
					EntityUtils.consume(response.getEntity());
					response.close();
				} catch (Exception e) {
					logger.error("关闭response失败:", e);
				}
			}
		}
		return jsonResult;
	}

	/**
	 * 处理https请求
	 * 
	 * @param requestUrl
	 * @param requestMethod
	 * @param jsonStr
	 * @return
	 */
	public static String httpsRequestXml(String requestUrl, String requestMethod, String xmlString) {
		StringBuffer buffer = new StringBuffer();
		try {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new HttpClientTools.CommonX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod))
				httpUrlConn.connect();

			// 当有数据需要提交时
			if (null != xmlString) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(xmlString.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			// JSONObject.fromObject(buffer.toString());
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
		return buffer.toString();
	}

	private static class CommonX509TrustManager implements X509TrustManager {

		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

		}

		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}

		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}

	}
}
